home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / dalla rivista / amiga.free / sorgenti vari / wolf3dmacsource.sit / Wolf3DMacSource / Mac.c < prev    next >
Text File  |  2000-01-21  |  62KB  |  2,197 lines

  1. /*********************
  2.  
  3.     Main Macintosh code
  4.  
  5. *********************/
  6.  
  7. #include "Wolfdef.h"        /* All the game equates */
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <setjmp.h>
  11. #include <palettes.h>
  12. #include <qdoffscreen.h>
  13. #include <Gestalt.h>
  14. #include "SoundMusicSystem.h"
  15. #include "PickAMonitor.h"
  16. #include "Hidemenubar.h"
  17. #include "Prefs.h"
  18. #include <AppleEvents.h>
  19.  
  20. static Word DoMyAlert(Word AlertNum);
  21. static void CenterSFWindow(Point *MyPoint,Word x,Word y);
  22. static void CenterAWindow(WindowPtr MyWindow);
  23. static void FixPauseMenu(void);
  24. Boolean LoadGame(void);
  25. pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit);
  26. Word ChooseGameDiff(void);
  27. Word DoEvent(EventRecord *event);
  28. void DoUpdate(WindowPtr window);
  29. void DrawWindow(WindowPtr window);
  30. void AdjustMenus(void);
  31. void DoMenuCommand(LongWord menuResult);
  32. Boolean DoCloseWindow(WindowPtr window);
  33. void InitTools(void);
  34. void SaveGame(void);
  35. void LoadPrefs(void);
  36. void SavePrefs(void);
  37. Boolean ChooseLoadGame(void);
  38. Boolean ChooseSaveGame(void);
  39. OSErr MyEventHandler(AppleEvent *MyAppleEvent,AppleEvent *AppleReply,long MyRefCon);
  40.  
  41. Boolean MouseHit;        /* True if a mouse was pressed */
  42. static MenuHandle PauseMenu;
  43. static Boolean WaitNextOK;        /* True if WaitNextEvent is present */
  44. static Boolean LowOnMem;        /* True if sound is disabled for low memory */
  45. static Boolean OpenPending;        /* True if a load game apple event occured */
  46. static Byte *SaveFileName;        /* Pointer to the save file name */
  47. static short SaveFileVol;        /* Directory referance for save file name */    
  48. static long SaveFileParID;        /* Parent directory id of save-game file */
  49. static Boolean ValidRects;        /* Are there blank rects in the window? */
  50. static RgnHandle BlackRgn;        /* Blank region for window blanking */
  51. static Rect QDGameRect;            /* Rect of the game playing area */
  52. static Rect GameRect = {0,0,200,320};    /* Size of the playfield */
  53. static Rect BlackRect = {0,0,480,640};    /* Rect for the Black Window (Set to main window size) */
  54. static Rect BlackRect2 = {0,0,480,640};    /* True rect for the Black window (Global) */
  55. static Word OldPixDepth;        /* Previous pixel depth of screen */
  56. Word MacWidth;                    /* Width of play screen (Same as GameRect.right) */
  57. Word MacHeight;                    /* Height of play screen (Same as GameRect.bottom) */
  58. Word MacViewHeight;                /* Height of 3d screen (Bottom of 3D view */
  59. static Word MonitorWidth=640;        /* Width of the monitor in pixels */
  60. static Word MonitorHeight=480;        /* Height of the monitor in pixels */
  61. Word QuitFlag;                    /* I quit if true */
  62. Word TrueVideoWidth;            /* Width of video monitor in bytes */
  63. Byte *TrueVideoPointer;            /* Pointer to the video monitor memory */
  64. Byte *GameVideoPointer;            /* Pointer to start of 3D view on monitor memory (Used by BlastScreen) */
  65. Boolean DoQuickDraw = TRUE;        /* Use quickdraw for updates? */    
  66. static Boolean DimQD;            /* Force QuickDraw forever! */
  67. Word IgnoreMessage;                /* Variable set by prefs to ignore messages */
  68. static CursHandle WatchHandle;    /* Handle to a watch cursor */
  69. #define RectX ((MonitorWidth-MacWidth)/2)
  70. #define RectY ((MonitorHeight-MacHeight)/2)
  71. Word VidXs[] = {320,512,640,640};    /* Screen sizes to play with */
  72. Word VidYs[] = {200,384,400,480};
  73. Word VidVs[] = {160,320,320,400};
  74. Word VidPics[] = {rFaceShapes,rFace512,rFace640,rFace640};        /* Resource #'s for art */
  75. static Word MouseBaseX;
  76. static Word MouseBaseY;
  77. static Boolean InPause;            /* Pause active? */
  78.  
  79. extern jmp_buf ResetJmp;
  80. extern Boolean JumpOK;
  81. extern CWindowPtr GameWindow;    /* Pointer to main game window */
  82. extern CGrafPtr GameGWorld;        /* Grafport to offscreen buffer */
  83. GDHandle gMainGDH;                /* Main graphics handle */
  84. CTabHandle MainColorHandle;        /* Main color table handle */
  85.  
  86. static void WaitCursor(void);
  87. static void ResetPalette(void);
  88. static void DoBackground(EventRecord *event);
  89. static void InitAEStuff(void);
  90. static void FixTheCursor(void);
  91.  
  92. /***************************
  93.  
  94.     Dialog filter for 68020/30 version speed warning
  95.  
  96. ***************************/
  97.  
  98. #ifndef __powerc
  99. static pascal Boolean InitFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  100. {
  101.     char    theChar;
  102.     Handle    theHandle;
  103.     short    theType;
  104.     Rect    theRect;
  105.  
  106.     switch (theEvent->what) {
  107.     case keyDown:
  108.         theChar = theEvent->message & charCodeMask;
  109.         switch (theChar) {
  110.         case 0x0D:        /* Return */
  111.         case 0x03:        /* Enter */
  112.             *itemHit = 1;
  113.             return (TRUE);
  114.         }
  115.  
  116.     case updateEvt:
  117.         GetDialogItem(theDialog,1, &theType, &theHandle, &theRect);
  118.         InsetRect(&theRect, -4, -4);
  119.         PenSize(3,3);
  120.         FrameRoundRect(&theRect, 16, 16);
  121.     }
  122.     return (FALSE);        /* Tells dialog manager to handle the event */
  123. }
  124. #endif
  125.  
  126. /***************************
  127.  
  128.     Init the Macintosh and all the
  129.     system tools
  130.  
  131. ***************************/
  132.  
  133. void InitTools(void)
  134. {
  135.     Handle menuBar;                /* Handle to menu bar record */
  136.     Word i;                        /* Temp */
  137.     long Feature;                /* Gestalt return value */
  138.     short int *SoundListPtr;    /* Pointer to sound list for Halestorm driver */
  139.  
  140.     MaxApplZone();    /* Expand the heap so code segments load at the top */
  141.     InitGraf((Ptr) &qd.thePort);    /* Init the graphics system */
  142.     InitFonts();                    /* Init the font manager */
  143.     InitWindows();                    /* Init the window manager */
  144.     InitMenus();                    /* Init the menu manager */
  145.     TEInit();                        /* Init text edit */
  146.     InitDialogs(nil);                /* Init the dialog manager */
  147.     i = 16;                            /* Make 64*16 handle records */
  148.     do {
  149.         MoreMasters();                /* Create a BUNCH of new handles */
  150.     } while (--i);
  151. #ifdef __powerc
  152.     WaitNextOK = TRUE;
  153. #else
  154.     if (NGetTrapAddress(0xA860,1) != (void *)0xa89F) {
  155.         WaitNextOK = TRUE;
  156.     }
  157. #endif
  158.  
  159.     InitAEStuff();                    /* Apple events shit */
  160.     InitCursor();                    /* Reset the cursor */
  161.     WatchHandle = GetCursor(watchCursor);    /* Get the watch cursor */
  162.     HLock((Handle)WatchHandle);        /* Lock it down */
  163.     WaitCursor();                    /* Set the watch cursor */
  164.     LoadPrefs();                    /* Load the prefs file */
  165.     
  166.     /* Now that the mac is started up, let's make sure I can run on this particular mac */
  167.  
  168. #ifndef __powerc        /* Power macs REQUIRE 7.1 to run so don't even check on power macs */
  169.  
  170.     if (Gestalt(gestaltVersion,&Feature)) {    /* Is gestalt working? */
  171.         goto Not607;            /* Oh oh... */
  172.     }
  173.         
  174.     /* Check for System 6.0.7 or later */
  175.     
  176.     if (Gestalt(gestaltSystemVersion, &Feature) ||
  177.         (short)Feature < 0x0607) {    /* Is it 6.0.7 or later? */
  178.         goto Not607;
  179.     }
  180.  
  181. #endif
  182.  
  183.     /* Check for Color QuickDraw.  If there's no color, quit.  Below, we check for
  184.         32-bit color QuickDraw.  */
  185.         
  186.     if (Gestalt(gestaltQuickdrawVersion, &Feature)) {
  187. Not607:
  188.         DoMyAlert(Not607Win);        /* Alert the user */
  189.         GoodBye();                /* Exit now */
  190.     }
  191.     
  192.     /* Check for 32-bit Color QuickDraw */
  193.     
  194.     if( (Feature & 0x0000ffff) < 0x0200) {    /* Not 32 bit? */
  195.         DoMyAlert(Not32QDWin);    /* I need 32 bit quickdraw! */
  196.         GoodBye();                /* Exit */
  197.     }
  198.     
  199.         /*  Check the Mac's processor.  If it's a 68030 or earlier, warn the user it
  200.         might be slow, and note the best ways to speed it up.  */
  201.     
  202. #ifndef __powerc        /* Power macs don't need this message */
  203.     Gestalt(gestaltProcessorType,&Feature);
  204.     i = 0;
  205.     switch(Feature) {
  206.     case gestalt68000:
  207.         ++i;
  208.         ParamText("\p68000","\p","\p","\p");
  209.         break;
  210.     case gestalt68020:
  211.         ++i;
  212.         ParamText("\p68020","\p","\p","\p");
  213.         break;
  214.     case gestalt68030:
  215.         ++i;
  216.         ParamText("\p68030","\p","\p","\p");
  217.         break;
  218.     }
  219.     
  220.     if (i && !IgnoreMessage) {
  221.         short     theValue,itemHit,iType;
  222.         Handle    iHndl;
  223.         Rect    iRect;
  224.         DialogPtr MyDialog;
  225.         ModalFilterUPP theDialogFilter;
  226.  
  227.         theDialogFilter = NewModalFilterProc(InitFilter);    /* Create a code pointer */
  228.         MyDialog = GetNewDialog(SlowWarnWin,0L,(WindowPtr)-1);    /* Load my dialog from disk */
  229.         CenterAWindow(MyDialog);
  230.         ShowWindow(MyDialog);    /* Display with OK button framed */
  231.         SetPort((WindowPtr) MyDialog);
  232.         InitCursor();                    /* Init the cursor */
  233.         do {
  234.             ModalDialog(theDialogFilter,&itemHit);        /* Handle the dialog */
  235.             if (itemHit==2) {        /* The checkbox */
  236.                 GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect);
  237.                 theValue = GetControlValue((ControlHandle)iHndl);
  238.                 SetControlValue( (ControlHandle) iHndl, !theValue );
  239.             }
  240.         } while (itemHit!=1);
  241.         GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect);    /* Get the check box state */
  242.         IgnoreMessage = GetControlValue((ControlHandle)iHndl);
  243.         if (IgnoreMessage) {        /* If I should ignore... */
  244.             SavePrefs();            /* Save the prefs file */
  245.         }
  246.         DisposeDialog(MyDialog);    /* Release the dialog memory */
  247.     }
  248. #endif
  249.     
  250. /* Let's set up the environment... */
  251.     
  252.     InitSoundMusicSystem(8,8,5,jxLowQuality);
  253.     PurgeSongs(TRUE);            /* Allow songs to stay in memory */
  254.     SoundListPtr = (short int *) LoadAResource(MySoundList);    /* Get the list of sounds */
  255.     RegisterSounds(SoundListPtr,FALSE);    
  256.     ReleaseAResource(MySoundList);            /* Release the sound list */
  257.     
  258.     GetTableMemory();            /* Get memory for far tables math tables */         
  259.     MapListPtr = (maplist_t *) LoadAResource(rMapList);    /* Get the map list */
  260.     SongListPtr = (unsigned short *) LoadAResource(rSongList);
  261.     WallListPtr = (unsigned short *) LoadAResource(MyWallList);
  262.  
  263. /* Alert the user that you MUST pay! */
  264.  
  265.     if (MapListPtr->MaxMap==3) {    /* Shareware version? */
  266.         DoMyAlert(ShareWareWin);    /* Show the shareware message */
  267.     }
  268.     if (FreeMem() < 3000000L) {        /* Are you low on memory? */            
  269.         DoMyAlert(LowMemWin);
  270.         SystemState = 0;            /* Turn off music and sound (Just in case) */
  271.         LowOnMem = TRUE;
  272.     }
  273.     ShowCursor();                    /* Make sure the cursor is ok */
  274.     WaitCursor();                    /* Restore the watch cursor */
  275.  
  276. /* Try to set up 8-bit color mode */
  277.  
  278.     gMainGDH = PickAMonitor(8,TRUE,512,384);    /* Pick a monitor to play on */
  279.     if (!gMainGDH) {            /* No macs that can display or canceled */
  280.         GoodBye();                /* Exit */
  281.     }
  282.     OldPixDepth = (**(**gMainGDH).gdPMap).pixelSize;        /* Get the previous mode */
  283.     if (OldPixDepth != 8) {                                    /* Was it 8 bit already? */
  284.          if (SetDepth(gMainGDH,8, 1 << gdDevType,1)) {        /* Set to 8 bit */
  285.             BailOut();                /* Oh oh... */
  286.          }
  287.     }
  288.     MainColorHandle = (*(*gMainGDH)->gdPMap)->pmTable;        /* Get my main device's color handle */
  289.     BlackRect2 = (**gMainGDH).gdRect;        /* Init the black rect */
  290.     LockPixels((**gMainGDH).gdPMap);    /* Lock down the memory FOREVER! */
  291.     TrueVideoPointer = (Byte *) GetPixBaseAddr((**gMainGDH).gdPMap);    /* Get pointer to screen mem */
  292.     TrueVideoWidth = (Word) ((**(**gMainGDH).gdPMap).rowBytes & 0x3FFF);    /* Get width of screen mem */
  293.  
  294.     if (!TrueVideoPointer || !TrueVideoWidth) {
  295.         DimQD = TRUE;                /* Don't allow offscreen drawing */
  296.         DoQuickDraw = TRUE;    /* Force QD */
  297.     }
  298.     MonitorHeight = BlackRect2.bottom - BlackRect2.top;    /* Get the size of the video screen */
  299.     MonitorWidth = BlackRect2.right - BlackRect2.left;
  300.     MouseBaseX = BlackRect2.left+256;
  301.     MouseBaseY = BlackRect2.top+192;
  302.     
  303.     menuBar = GetNewMBar(MyMenuBar);    /* read menus into menu bar */
  304.     if (!menuBar) {
  305.         BailOut();            /* Menu bar error */
  306.     }    
  307.     SetMenuBar(menuBar);            /* install menus */
  308.     DisposeHandle(menuBar);            /* Release the menu bar */
  309.     AppendResMenu(GetMenuHandle(mApple),'DRVR');    /* add DA names to Apple menu */
  310.     DrawMenuBar();                /* Show the menu bar */
  311.     HideMenuBar();            /* Hide the menu bar */
  312.  
  313.     GameWindow = (CWindowPtr)NewCWindow(nil,&BlackRect2, "\p",TRUE, plainDBox, (WindowPtr) -1L, FALSE, 0);
  314.     if (!GameWindow) {        /* No background window? */
  315.         BailOut();
  316.     }
  317.     BlackRgn = NewRgn();    /* Make a region for the black area */
  318.     SetPort((WindowPtr)GameWindow);        /* Use this grafport */
  319.     ActivatePalette((WindowPtr)GameWindow);
  320.     BlackRect.top = 0;                /* Init the main rect */
  321.     BlackRect.left = 0;
  322.     BlackRect.bottom = MonitorHeight;
  323.     BlackRect.right = MonitorWidth;
  324.     FillRect(&BlackRect,&qd.black);    /* Erase the screen to black */
  325.     NewGameWindow(1);                /* Create a game window at 512x384 */
  326.     ClearTheScreen(BLACK);            /* Force the offscreen memory blank */
  327.     BlastScreen();
  328.     FixTheCursor();                    /* Fix the cursor */
  329. }
  330.  
  331. /************************************
  332.  
  333.     Set the hardware palette to match my window palette for high speed
  334.     copybits operation
  335.     
  336. ************************************/
  337.  
  338. extern Byte CurrentPal[768];        /* Last palette the game was set to */
  339.  
  340. static void ResetPalette(void)
  341. {    
  342.     SetPort((WindowPtr) GameWindow);        /* Reset the game window */
  343.     if ((**(**gMainGDH).gdPMap).pixelSize != 8) {        /* Get the previous mode */
  344.         SetDepth(gMainGDH,8, 1 << gdDevType,1);        /* Set to 8 bit color */
  345.     }
  346.     SetAPalettePtr(CurrentPal);                /* Restore the palette */
  347. }
  348.  
  349. /************************************
  350.  
  351.     Process the suspend/resume events
  352.     
  353. ************************************/
  354.  
  355. static void DoBackground(EventRecord *event)
  356. {
  357.     EventRecord PauseEvent;
  358.  
  359.     if ((event->message & 0xff000000) ==0x01000000) {        /* Suspend/Resume events */
  360.         if (!(event->message & resumeFlag)) {        /* Suspend event? */
  361.             if (!InPause) {
  362.                 PauseSoundMusicSystem();        /* Stop the music */
  363.                 ShowMenuBar();    /* Display the menu bar */
  364.             }
  365.             InitCursor();    /* Restore the arrow cursor */
  366.     
  367.         /*    Call a new event loop while in background to let us know when we've returned. */
  368.                 
  369.             do {
  370.                 WaitNextEvent2(everyEvent, &PauseEvent, 0xFF, nil);
  371.                 if (PauseEvent.what==updateEvt) {        /* Time for update? */
  372.                     DoUpdate((WindowPtr) PauseEvent.message);    /* Redraw the window */
  373.                 }
  374.             } while (PauseEvent.what!=mouseDown && PauseEvent.what!=activateEvt && PauseEvent.what!=app4Evt);
  375.     
  376.     /*    Turn the main game window back on and update its contents. */
  377.  
  378.             ResetPalette();        /* Reset the game palette */
  379.             FixTheCursor();        /* Make it disappear for game if needed */
  380.             if (!InPause) {        
  381.                 HideMenuBar();            /* Make the menu bar disappear */
  382.                 ResumeSoundMusicSystem();    /* Restart the music */
  383.             }
  384.         }
  385.     }
  386. }
  387.  
  388. /************************************
  389.  
  390.     Call Wait next event if present
  391.  
  392. ************************************/
  393.  
  394. Boolean WaitNextEvent2(short EventMask,EventRecord *theEvent,long sleep,RgnHandle mouseRgn)
  395. {
  396.     if (WaitNextOK) {
  397.         return WaitNextEvent(EventMask,theEvent,sleep,mouseRgn);
  398.     }
  399.     SystemTask();
  400.     return GetNextEvent(EventMask,theEvent);    
  401. }
  402.  
  403. /************************************
  404.  
  405.     Execute the apple event
  406.     
  407. ************************************/
  408.  
  409. static void HandleHighLevelEvent(EventRecord *event)
  410. {
  411.     AEProcessAppleEvent(event);
  412.     if (QuitFlag) {
  413.         GoodBye();
  414.     }
  415. }
  416.  
  417. /************************************
  418.  
  419.     Do the right thing for an event. Determine what kind of
  420.     event it is, and call the appropriate routines.
  421.     This is like TaskMaster for the IIgs
  422.  
  423. ************************************/
  424.  
  425. Word DoEvent(EventRecord *event)
  426. {
  427.     Word part;
  428.     WindowPtr    window;
  429.     Word key;
  430.     Point aPoint;
  431.     
  432.     switch (event->what) {    /* Process the event */
  433.     case kHighLevelEvent:        /* Apple events? */
  434.         HandleHighLevelEvent(event);    /* Pass it on... */
  435.         break;
  436.                 
  437.     case mouseDown:    /* Pressed the mouse? */
  438.         FixMHeight();        /* Allow menu bar clicks */
  439.         part = FindWindow(event->where, &window);    /* Choose the hit */
  440.         ZapMHeight();        /* Don't click anymore */
  441.         switch (part) {
  442.         case inMenuBar:            /* process a mouse menu command (if any) */
  443.             AdjustMenus();        /* Enable/disable menu items */
  444.             ShowMenuBar();        /* Display the menu bar */
  445.             DoMenuCommand(MenuSelect(event->where));    /* Handle the command */
  446.             if (!InPause) {
  447.                 HideMenuBar();        /* Hide the menu bar */
  448.             }
  449.             break;
  450.         case inSysWindow:            /* let the system handle the mouseDown */
  451.             SystemClick(event, window);    /* Pass on the event */
  452.             break;
  453.         case inContent:
  454.             if (window != FrontWindow() ) {
  455.                 SelectWindow(window);    /* Make it the front window */
  456.             }
  457.             if (window == (WindowPtr)GameWindow) {
  458.                 MouseHit = TRUE;
  459.             }
  460.             break;
  461.         case inDrag:        /* pass screenBits.bounds to get all gDevices */
  462.             DragWindow(window, event->where, &qd.screenBits.bounds);
  463.             break;
  464.         case inGoAway:
  465.             if (TrackGoAway(window,event->where)) {    /* Handle the close box */
  466.                 DoCloseWindow(window);    /* Close my window */
  467.             }
  468.             break;
  469.         case inZoomIn:
  470.         case inZoomOut:
  471.             if (TrackBox(window, event->where, part)) {    /* Track the zoom box */
  472.                 SetPort(window);                /* the window must be the current port... */
  473.                 EraseRect(&window->portRect);    /* because of a bug in ZoomWindow */
  474.                 ZoomWindow(window,part,TRUE);    /* note that we invalidate and erase... */
  475.                 InvalRect(&window->portRect);    /* to make things look better on-screen */
  476.             }
  477.             break;
  478.         }
  479.         break;
  480.     case keyDown:
  481.     case autoKey:                        /* check for menukey equivalents */
  482.         key = event->message & charCodeMask;
  483.         if (event->modifiers & cmdKey) {            /* Command key down */
  484.             if (event->what == keyDown) {
  485.                 AdjustMenus();        /* enable/disable/check menu items properly */
  486.                 DoMenuCommand(MenuKey(key));    /* Process the key */
  487.             }
  488.             return 0;    /* Ignore the event */
  489.         }
  490.         return key;        /* Return the key pressed */
  491.     case updateEvt:
  492.         DoUpdate((WindowPtr) event->message);    /* Force redraw of my window */
  493.         break;
  494.     case diskEvt:
  495.         if ((event->message>>16) != noErr ) {    /* Was there an error? */
  496.             SetPt(&aPoint, kDILeft, kDITop);
  497.             DIBadMount(aPoint, event->message);    /* Format the disk? */
  498.         }
  499.         break;
  500.     case activateEvt:
  501.         if (event->modifiers & 1) {
  502.             FixTheCursor();        /* Reset the cursor to the hidden state */
  503.             SetPort((WindowPtr)GameWindow);
  504.             ResetPalette();        /* Set my system palette */
  505.         }
  506.         break;
  507.     case osEvt:    
  508.         DoBackground(event);            /* Process suspend / resume */
  509.         break;
  510.     }
  511.     if (OpenPending && JumpOK) {    
  512.         OpenPending=FALSE;                /* Ack the event */
  513.         if (LoadGame()) {                /* Load the game into memory */
  514.             longjmp(ResetJmp,EX_LOADGAME);    /* Restart a loaded game */
  515.         }
  516.     }
  517.     if (!InPause) {
  518.         HideMenuBar();            /* Make SURE the menu bar is gone! */
  519.     }
  520.     return 0;                /* No event processed */
  521. }
  522.  
  523. /**********************************
  524.  
  525.     Call this when I receive an update event
  526.     
  527. **********************************/
  528.  
  529. void DoUpdate(WindowPtr window)
  530. {
  531.     if (((WindowPeek) window)->windowKind >=0) {    /* Is this my window? */
  532.         BeginUpdate(window);            /* this sets up the visRgn */
  533.         DrawWindow(window);                /* Draw the game window */
  534.         EndUpdate(window);                /* Fix the visRgn */
  535.     }
  536. }
  537.  
  538. /************************
  539.  
  540.     Update the contents of the window
  541.  
  542. ************************/
  543.  
  544. void DrawWindow(WindowPtr window)
  545. {
  546.     Word OldQuick;                /* Previous state of the quickdraw flag */
  547.     if (window == (WindowPtr) GameWindow) {    /* Is it my window? */
  548.         SetPort((WindowPtr)GameWindow);
  549.         OldQuick = DoQuickDraw;    /* Save the quickdraw flag */
  550.         DoQuickDraw = TRUE;        /* Force quickdraw */
  551.         BlastScreen();            /* Update the screen */
  552.         DoQuickDraw = OldQuick;    /* Restore quickdraw flag */
  553.         if (ValidRects) {        /* Black region valid? */
  554.             FillRgn(BlackRgn,&qd.black);        /* Fill the black region */
  555.         }
  556.     }
  557. }
  558.  
  559. /****************************
  560.  
  561.     Set an item's mark with a check mark
  562.  
  563. ****************************/
  564.  
  565. static void SetAMark(MenuHandle MyHand,Word Which,Word Var)
  566. {
  567.     Var = (Var) ? 0x12 : 0;
  568.     SetItemMark(MyHand,Which,Var);
  569. }
  570.  
  571. /****************************
  572.  
  573.     Enable and disable menu items
  574.  
  575. ****************************/
  576.  
  577. void AdjustMenus(void)
  578. {
  579.     WindowPtr window;
  580.     MenuHandle FileMenu,EditMenu,OptionMenu;
  581.     
  582.     window = FrontWindow();            /* Which window is in front */
  583.     FileMenu = GetMenuHandle(mFile);        /* Get the file menu handle */
  584.     EditMenu = GetMenuHandle(mEdit);    /* Get the edit menu handle */
  585.     OptionMenu = GetMenuHandle(mOptions);
  586.     if (window!=(WindowPtr)GameWindow) {    /* Enable if there is a window */
  587.         EnableItem(FileMenu,iClose);
  588.         EnableItem(EditMenu,0);
  589.     } else {
  590.         DisableItem(FileMenu,iClose);
  591.         DisableItem(EditMenu,0);
  592.     }
  593.     if (playstate == EX_STILLPLAYING) {    /* Game is in progress */
  594.         EnableItem(FileMenu,iSaveAs);    /* Save the game */
  595.         EnableItem(FileMenu,iSave);        /* Quicksave the game */
  596.     } else {
  597.         DisableItem(FileMenu,iSaveAs);    /* Can't save game when isn't in the mode */
  598.         DisableItem(FileMenu,iSave);
  599.     }
  600.     if (LowOnMem) {
  601.         DisableItem(OptionMenu,iSound);
  602.         DisableItem(OptionMenu,iMusic);
  603.     }
  604.     if (DimQD) {
  605.         DisableItem(OptionMenu,iUseQuickDraw);
  606.     }
  607.     if (playstate==EX_AUTOMAP || playstate==EX_DIED) {
  608.         DisableItem(OptionMenu,iScreenSize);
  609.     } else {
  610.         EnableItem(OptionMenu,iScreenSize);
  611.     }
  612.     SetAMark(OptionMenu,iSound,SystemState&SfxActive);    /* Check the sound menu */
  613.     SetAMark(OptionMenu,iMusic,SystemState&MusicActive);    /* Check the music menu */
  614.     SetAMark(OptionMenu,iGovenor,SlowDown);            /* Check the Speed goveror */
  615.     SetAMark(OptionMenu,iMouseControl,MouseEnabled);                /* Check the mouse flag */
  616.     SetAMark(OptionMenu,iUseQuickDraw,DoQuickDraw);                /* Check the mouse flag */
  617. }
  618.  
  619. /**********************************
  620.  
  621.     Process a menu bar event
  622.  
  623. **********************************/
  624.  
  625. void DoMenuCommand(LongWord menuResult)
  626. {
  627.     Word menuID;            /* the resource ID of the selected menu */
  628.     Word menuItem;            /* the item number of the selected menu */
  629.     Str255 daName;            /* Name of desk acc */
  630.     Word i;                    /* Temp */
  631.     
  632.     menuID = menuResult>>16;    
  633.     menuItem = menuResult&0xffff;    /* get menu item number and menu number */
  634.     switch (menuID) {
  635.     case mApple:                /* Apple menu */
  636.         switch (menuItem) {
  637.         case iAbout:        /* Bring up alert for About */
  638.             PlaySound(SND_MENU);
  639.             DoMyAlert(rAboutAlert);        /* Show the credits */
  640.             PlaySound(SND_OK);
  641.             break;
  642.         case iSpeedHint:    
  643.             PlaySound(SND_MENU);
  644.             DoMyAlert(SpeedTipsWin);    /* Show the hints for speed */
  645.             PlaySound(SND_OK);
  646.             break;
  647.         case iShareWare:
  648.             PlaySound(SND_MENU);
  649.             DoMyAlert(ShareWareWin);    /* Ask about $$$ */
  650.             PlaySound(SND_OK);
  651.             break;
  652.         default:            /* all non-About items in this menu are DAs */
  653.             GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  654.             OpenDeskAcc(daName);
  655.             break;
  656.         }
  657.         break;
  658.     case mFile:                /* File menu */
  659.         switch (menuItem) {
  660.         case iNew:    
  661.             if (ChooseGameDiff()) {        /* Choose level of difficulty */
  662.                 HiliteMenu(0);
  663.                 FixPauseMenu();
  664.                 SaveFileName = 0;        /* Zap the save game name */
  665.                 longjmp(ResetJmp,EX_NEWGAME);
  666.             }
  667.             break;
  668.         case iClose:
  669.             DoCloseWindow(FrontWindow());
  670.             break;
  671.         case iOpen:
  672.             if (ChooseLoadGame()) {        /* Choose a game to load */
  673.                 if (LoadGame()) {                /* Load the game into memory */
  674.                     HiliteMenu(0);
  675.                     FixPauseMenu();
  676.                     longjmp(ResetJmp,EX_LOADGAME);    /* Restart a loaded game */
  677.                 }
  678.             }
  679.             break;
  680.         case iSave:
  681.             if (SaveFileName) {            /* Save the file automatically? */
  682.                 SaveGame();                /* Save it */
  683.                 break;
  684.             }
  685.         case iSaveAs:
  686.             if (ChooseSaveGame()) {        /* Select a save game name */
  687.                 SaveGame();                /* Save it */
  688.             }
  689.             break;
  690.         case iQuit:
  691.             GoodBye();    /* Try to quit */
  692.             break;
  693.         }
  694.         break;
  695.     case mEdit:        /* call SystemEdit for DA editing & MultiFinder */
  696.         SystemEdit(menuItem-1);    /* since we don't do any Editing */
  697.         break;
  698.     case mOptions:
  699.         switch (menuItem) {
  700.         case iSound:
  701.             SystemState^=SfxActive;                /* Sound on/off flags */
  702.             if (!(SystemState&SfxActive)) {
  703.                 if (InPause) {
  704.                     ResumeSoundMusicSystem();
  705.                 }
  706.                 PlaySound(0);            /* Turn off all existing sounds */
  707.                 if (InPause) {
  708.                     PauseSoundMusicSystem();
  709.                 }
  710.             }
  711.             break;
  712.         case iMusic:
  713.             SystemState^=MusicActive;            /* Music on/off flags */
  714.             if (InPause) {
  715.                 ResumeSoundMusicSystem();
  716.             }
  717.             if (SystemState&MusicActive) {
  718.                 PlaySong(KilledSong);        /* Restart the music */
  719.             } else {
  720.                 PlaySong(0);    /* Shut down the music */
  721.             }
  722.             if (InPause) {
  723.                 PauseSoundMusicSystem();
  724.             }
  725.             break;
  726.         case iScreenSize:
  727.             i = DoMyAlert(AskSizeWin);        /* Should I change the size? */
  728.             if (i && i<5) {
  729.                 --i;
  730.                 if (GameViewSize!=i) {        /* Did you change the size? */
  731.                     if (!InPause) {
  732.                         HideMenuBar();
  733.                     }
  734.                     MouseHit = TRUE;        /* Get out of pause mode */
  735.                     GameViewSize = i;        /* Set the new size */
  736.                     if (playstate==EX_STILLPLAYING || playstate==EX_AUTOMAP) {
  737. TryIt:
  738.                         GameViewSize = NewGameWindow(GameViewSize);        /* Make a new window */
  739.                         if (!StartupRendering(GameViewSize)) {    /* Set the size of the game screen */
  740.                             ReleaseScalers();
  741.                             if (!GameViewSize) {
  742.                                 BailOut();
  743.                             }
  744.                             --GameViewSize;
  745.                             goto TryIt;
  746.                         }
  747.                         if (playstate==EX_STILLPLAYING) {
  748.                             RedrawStatusBar();        /* Redraw the lower area */
  749.                         }
  750.                         playstate=EX_STILLPLAYING;
  751.                         SetAPalette(rGamePal);            /* Reset the game palette */
  752.                     }
  753.                 }
  754.             }
  755.             break;
  756.         case iGovenor:
  757.             SlowDown^=1;        /* Toggle the slow down flag */
  758.             break;
  759.         case iMouseControl:
  760.             MouseEnabled = (!MouseEnabled);    /* Toggle the cursor */
  761.             FixTheCursor();
  762.             if (MouseEnabled) {
  763.                 ReadSystemJoystick();
  764.                 mousex = 0;
  765.                 mousey = 0;
  766.                 mouseturn=0;
  767.                 ReadSystemJoystick();
  768.                 mousex =0;        /* Discard the results */
  769.                 mousey =0;
  770.                 mouseturn=0;
  771.             } 
  772.             break;
  773.         case iUseQuickDraw:
  774.             DoQuickDraw^=TRUE;        /* Toggle the quickdraw flag */
  775.             break;
  776.         }
  777.         SavePrefs();
  778.         break;
  779.     }
  780.     HiliteMenu(0);        /* unhighlight what MenuSelect (or MenuKey) hilited */
  781. }
  782.  
  783. /*********************************
  784.  
  785.     Close a window, return TRUE if successful
  786.  
  787. *********************************/
  788.  
  789. Boolean DoCloseWindow(WindowPtr window)
  790. {
  791.     int Kind;
  792.  
  793.     if (window) {        /* Valid pointer? */
  794.         Kind = ((WindowPeek) window)->windowKind;    /* Get the kind */
  795.         if (Kind<0) {
  796.             CloseDeskAcc(Kind);
  797.         }
  798.     }
  799.     return TRUE;    /* I closed it! */
  800. }
  801.  
  802. /***************************
  803.  
  804.     I can't load! Bail out now!
  805.  
  806. ****************************/
  807.  
  808. void BailOut(void)
  809. {
  810.     DoMyAlert(rUserAlert);        /* Show the alert window */
  811.     GoodBye();                /* Bail out! */
  812. }
  813.  
  814. /**********************************
  815.  
  816.     Update the wolf screen as fast as possible
  817.  
  818.     Make sure that ForeColor = BLACK and Color = WHITE,
  819.     ROWBYTES should be long aligned (4,8,12,16...)
  820.     Source and dest should be EXACTLY the same bit depth
  821.     ctSeed should match the WINDOW's color seed
  822.     Both rects should be multiples of 4 to make long word transfers only
  823.  
  824. **********************************/
  825.  
  826. void BlastScreen2(Rect *BlastRect) 
  827. {
  828.     Rect QDRect;
  829.     CTabHandle ColorHandle,ColorHandle2;
  830.  
  831.     QDRect = *BlastRect;
  832.     OffsetRect(&QDRect,QDGameRect.left,QDGameRect.top);
  833.     SetPort((WindowPtr) GameWindow);        /* Make sure the port is set */
  834.     ColorHandle = (**(*GameGWorld).portPixMap).pmTable;    /* Get the color table */
  835.     ColorHandle2 = (**(*GameWindow).portPixMap).pmTable;    /* Get the color table */
  836.     PtrToXHand(*MainColorHandle,(Handle)ColorHandle,8+8*256);
  837.     PtrToXHand(*MainColorHandle,(Handle)ColorHandle2,8+8*256);
  838.     CopyBits((BitMap *) *((*GameGWorld).portPixMap),(BitMap *) *((*GameWindow).portPixMap),
  839.         BlastRect,&QDRect,srcCopy,NULL);
  840.  
  841. }
  842.  
  843. void BlastScreen(void)
  844. {
  845.     Word i,j,k,m;
  846.     Byte *Screenad;
  847.     LongWord *Dest;
  848.     union {
  849.         LongWord * L;
  850.         Byte *B;
  851.     } Src;
  852.     Point MyPoint;
  853.     
  854.     MyPoint.h = BlackRect2.left;
  855.     MyPoint.v = BlackRect2.top;
  856.     ShieldCursor(&GameRect,MyPoint);
  857.     if (!DoQuickDraw) {    
  858.         i = MacHeight;
  859.         k = MacWidth/64;
  860.         m = VideoWidth - MacWidth;
  861.         Src.B = VideoPointer;    /* Pointer to video */
  862.         Screenad = GameVideoPointer;        /* Get dest video address */
  863.         do {
  864.             j = k;        /* Init width (In Longs) */
  865.             Dest = (LongWord *) Screenad;    /* Reset the dest pointer */
  866.             do {
  867.                 Dest[0] = Src.L[0];
  868.                 Dest[1] = Src.L[1];
  869.                 Dest[2] = Src.L[2];
  870.                 Dest[3] = Src.L[3];
  871.                 Dest[4] = Src.L[4];
  872.                 Dest[5] = Src.L[5];
  873.                 Dest[6] = Src.L[6];
  874.                 Dest[7] = Src.L[7];
  875.                 Dest[8] = Src.L[8];
  876.                 Dest[9] = Src.L[9];
  877.                 Dest[10] = Src.L[10];
  878.                 Dest[11] = Src.L[11];
  879.                 Dest[12] = Src.L[12];
  880.                 Dest[13] = Src.L[13];
  881.                 Dest[14] = Src.L[14];
  882.                 Dest[15] = Src.L[15];
  883.                 Dest+=16;
  884.                 Src.L+=16;
  885.             } while (--j);
  886.             Src.B += m;
  887.             Screenad+=TrueVideoWidth;
  888.         } while (--i); 
  889.     } else {
  890.         BlastScreen2(&GameRect);
  891.     }
  892.     ShowCursor();
  893.     if (!InPause) {
  894.         ObscureCursor();
  895.     }
  896. }
  897.  
  898. /**********************************
  899.  
  900.     Create a new game window
  901.  
  902. **********************************/
  903.  
  904. Word NewGameWindow(Word NewVidSize)
  905. {            
  906.     Byte *DestPtr;
  907.     LongWord *LongPtr;
  908.     Word i,j;
  909.     Boolean Pass2;
  910.     RgnHandle TempRgn;
  911.     
  912.     Pass2 = FALSE;        /* Assume memory is OK */
  913.     
  914.     /* First, kill ALL previous permenant records */
  915.  
  916.     if (NewVidSize>=2) {    /* Is this 640 mode? */
  917.         if (MonitorWidth<640) {    /* Can I show 640 mode? */
  918.             NewVidSize=1;    /* Reduce to 512 mode */
  919.         } else {
  920.             if (MonitorHeight<480) {    /* Can I display 480 lines? */
  921.                 NewVidSize=2;    /* Show 400 instead */
  922.             }
  923.         }
  924.     }
  925.     if (NewVidSize==MacVidSize) {    /* Same size being displayed? */
  926.         return MacVidSize;                /* Exit then... */
  927.     }
  928.     SetPort((WindowPtr)GameWindow);        /* Blank out the screen! */
  929.     ForeColor(blackColor);        /* Make sure the colors are set */
  930.     BackColor(whiteColor);
  931.     FillRect(&BlackRect,&qd.black);    /* Blank it out! */
  932.  
  933. TryAgain:
  934.     if (GameGWorld) {
  935.         DisposeGWorld(GameGWorld);        /* Release the old GWorld */
  936.         GameGWorld=0;
  937.     }
  938.     if (GameShapes) {
  939.         FreeSomeMem(GameShapes);    /* All the permanent game shapes */
  940.         GameShapes=0;
  941.     }
  942.     MacVidSize = NewVidSize;    /* Set the new data size */
  943.     MacWidth = VidXs[NewVidSize];
  944.     MacHeight = VidYs[NewVidSize];
  945.     MacViewHeight = VidVs[NewVidSize];
  946.     
  947.     GameRect.bottom = MacHeight;    /* Set new video height */
  948.     GameRect.right = MacWidth;        /* Set new video width */
  949.     QDGameRect.top = RectY;
  950.     QDGameRect.left = RectX;
  951.     QDGameRect.bottom = RectY+MacHeight;
  952.     QDGameRect.right = RectX+MacWidth;
  953.  
  954.     if (MacHeight==MonitorHeight && MacWidth==MonitorWidth) {
  955.         ValidRects = FALSE;
  956.     } else {
  957.         ValidRects = TRUE;            /* The 4 bar rects are valid */
  958.         RectRgn(BlackRgn,&BlackRect);
  959.         TempRgn = NewRgn();
  960.         RectRgn(TempRgn,&QDGameRect);
  961.         DiffRgn(BlackRgn,TempRgn,BlackRgn);
  962.         DisposeRgn(TempRgn);
  963.     }
  964.     
  965.     GameVideoPointer = &TrueVideoPointer[(LongWord)QDGameRect.top*TrueVideoWidth+QDGameRect.left];
  966.     if (NewGWorld(&GameGWorld,8,&GameRect,nil,nil,0)) {
  967.         goto OhShit;
  968.     }
  969.     LockPixels(GameGWorld->portPixMap);    /* Lock down the memory FOREVER! */
  970.     VideoPointer = (Byte *)GetPixBaseAddr(GameGWorld->portPixMap);    /* Get the video pointer */
  971.     VideoWidth = (Word) (**(*GameGWorld).portPixMap).rowBytes & 0x3FFF;
  972.     InitYTable();                /* Init the game's YTable */
  973.     SetAPalette(rBlackPal);        /* Set the video palette */
  974.     ClearTheScreen(BLACK);        /* Set the screen to black */
  975.     BlastScreen();
  976.     
  977.     LongPtr = (LongWord *) LoadAResource(VidPics[MacVidSize]);
  978.     if (!LongPtr) {
  979.         goto OhShit;
  980.     }
  981.     GameShapes = (Byte **) AllocSomeMem(LongPtr[0]);    /* All the permanent game shapes */
  982.     if (!GameShapes) {        /* Can't load in the shapes */
  983.         ReleaseAResource(VidPics[MacVidSize]);    /* Release it NOW! */
  984.         goto OhShit;
  985.     }
  986.     DLZSS((Byte *)GameShapes,(Byte *) &LongPtr[1],LongPtr[0]);
  987.     ReleaseAResource(VidPics[MacVidSize]);
  988.     i = 0;
  989.     j = (MacVidSize==1) ? 47+10 : 47;        /* 512 mode has 10 shapes more */
  990.     DestPtr = (Byte *) GameShapes;
  991.     LongPtr = (LongWord *) GameShapes;
  992.     do {
  993.         GameShapes[i] = DestPtr+LongPtr[i]; 
  994.     } while (++i<j);
  995.     if (Pass2) {        /* Low memory? */
  996.         if (!StartupRendering(NewVidSize)) {        /* Reset the scalers... */
  997.             ReleaseScalers();
  998.             goto OhShit;
  999.         }
  1000.     }
  1001.     return MacVidSize;
  1002.     
  1003. OhShit:            /* Oh oh.... */
  1004.     if (Pass2) {
  1005.         if (!NewVidSize) {        /* At the smallest screen size? */
  1006.             BailOut();    
  1007.         }
  1008.         --NewVidSize;            /* Smaller size */
  1009.     } else {
  1010.         PlaySong(0);            /* Release song memory */
  1011.         ReleaseScalers();        /* Release the compiled scalers */
  1012.         PurgeAllSounds(1000000);    /* Force sounds to be purged */
  1013.         Pass2 = TRUE;
  1014.     }
  1015.     goto TryAgain;                /* Let's try again */
  1016. }
  1017.  
  1018. /**********************************
  1019.  
  1020.     Scale the system X coord
  1021.     
  1022. **********************************/
  1023.  
  1024. Word ScaleX(Word x)
  1025. {
  1026.     switch(MacVidSize) {
  1027.     case 1:
  1028.         return x*8/5;
  1029.     case 2:
  1030.     case 3:
  1031.         return x*2;
  1032.     }
  1033.     return x;
  1034. }
  1035.  
  1036. /**********************************
  1037.  
  1038.     Scale the system Y coord
  1039.     
  1040. **********************************/
  1041.  
  1042. Word ScaleY(Word y)
  1043. {
  1044.     switch(MacVidSize) {
  1045.     case 1:                /* 512 resolution */
  1046.         y = (y*8/5)+64;
  1047.         if (y==217) {    /* This hack will line up the gun on 512 mode */
  1048.             ++y;
  1049.         }
  1050.         return y;
  1051.     case 2:                /* 640 x 400 */
  1052.         return y*2;    
  1053.     case 3:                /* 640 x 480 */
  1054.         return y*2+80;
  1055.     }
  1056.     return y;            /* 320 resolution */
  1057. }
  1058.  
  1059. /**********************************
  1060.  
  1061.     Shut down and exit
  1062.     
  1063. **********************************/
  1064.  
  1065. void GoodBye(void)
  1066. {
  1067.     ShowMenuBar();                /* Restore the menu bar */
  1068.     ReleaseScalers();            /* Release all my memory */
  1069.     FinisSoundMusicSystem();        /* Shut down the Halestorm driver */
  1070.     if (gMainGDH && OldPixDepth) {    /* Old pixel depth */
  1071.         SetDepth(gMainGDH,OldPixDepth, 1 << gdDevType,1);    /* Restore the depth */
  1072.     }
  1073.     InitCursor();
  1074.     ExitToShell();                /* Exit to System 7 */
  1075. }
  1076.  
  1077. /**********************************
  1078.  
  1079.     Read from the Mac's keyboard/mouse system
  1080.     
  1081. **********************************/
  1082.  
  1083. Word MyKey;
  1084.  
  1085. typedef struct MacKeys2Joy {
  1086.     Word Index;
  1087.     Word BitField;
  1088.     Word JoyValue;
  1089. } MacKeys2Joy;
  1090.  
  1091. MacKeys2Joy KeyMatrix[] = {
  1092.     {11,1<<1,JOYPAD_LFT|JOYPAD_UP},        /* Keypad 7 */
  1093.     {10,1<<6,JOYPAD_LFT},                /* Keypad 4 */
  1094.     {10,1<<3,JOYPAD_LFT|JOYPAD_DN},        /* Keypad 1 */
  1095.     {11,1<<3,JOYPAD_UP},                /* Keypad 8 */
  1096.     {10,1<<7,JOYPAD_DN},                /* Keypad 5 */
  1097.     {10,1<<4,JOYPAD_DN},                /* Keypad 2 */
  1098.     {11,1<<4,JOYPAD_RGT|JOYPAD_UP},        /* Keypad 9 */
  1099.     {11,1<<0,JOYPAD_RGT},                /* Keypad 6 */
  1100.     {10,1<<5,JOYPAD_RGT|JOYPAD_DN},        /* Keypad 3 */
  1101.     {15,1<<6,JOYPAD_UP},                /* Arrow up */
  1102.     {15,1<<5,JOYPAD_DN},                /* Arrow down */
  1103.     {15,1<<3,JOYPAD_LFT},                /* Arrow Left */
  1104.     {15,1<<4,JOYPAD_RGT},                /* Arrow Right */
  1105.     { 1,1<<5,JOYPAD_UP},            /* W */
  1106.     { 0,1<<0,JOYPAD_LFT},            /* A */
  1107.     { 0,1<<1,JOYPAD_DN},            /* S */
  1108.     { 0,1<<2,JOYPAD_RGT},            /* D */
  1109.     { 4,1<<2,JOYPAD_UP},            /* I */
  1110.     { 4,1<<6,JOYPAD_LFT},            /* J */
  1111.     { 5,1<<0,JOYPAD_DN},            /* K */
  1112.     { 4,1<<5,JOYPAD_RGT},            /* L */
  1113.     { 6,1<<1,JOYPAD_A},                /* Space */
  1114.     { 4,1<<4,JOYPAD_A},                /* Return */
  1115.     {10,1<<2,JOYPAD_A},                /* Keypad 0 */
  1116.     { 9,1<<4,JOYPAD_A},                /* keypad enter */
  1117.     { 7,1<<7,JOYPAD_TR},            /* Option */
  1118.     { 7,1<<2,JOYPAD_TR},            /* Option */    
  1119.     { 7,1<<0,JOYPAD_X},                /* Shift L */
  1120.     { 7,1<<1,JOYPAD_X},                /* Caps Lock */
  1121.     { 7,1<<4,JOYPAD_X},                /* Shift R */
  1122.     { 6,1<<0,JOYPAD_SELECT},        /* Tab */
  1123.     { 7,1<<3,JOYPAD_B},                /* Ctrl */
  1124.     { 7,1<<6,JOYPAD_B}                /* Ctrl */
  1125. };
  1126.  
  1127. static char *CheatPtr[] = {        /* Cheat strings */
  1128.     "XUSCNIELPPA",    
  1129.     "IDDQD",
  1130.     "BURGER",
  1131.     "WOWZERS",
  1132.     "LEDOUX",
  1133.     "SEGER",
  1134.     "MCCALL",
  1135.     "APPLEIIGS"
  1136. };
  1137. static Word Cheat;            /* Which cheat is active */
  1138. static Word CheatIndex;    /* Index to the cheat string */
  1139.  
  1140. static void FixPauseMenu(void)
  1141. {
  1142.     if (PauseMenu) {    /* Is there a pause menu? */
  1143.         InPause = FALSE;
  1144.         DeleteMenu(55);    /* Remove it from the menu bar */
  1145.         DrawMenuBar();    /* Redraw the menu bar */
  1146.         HideMenuBar();    /* Hide the menu bar */
  1147.         DisposeMenu(PauseMenu);    /* Free the memory */
  1148.         PauseMenu = 0;    /* Ack the flag */
  1149.         ResumeSoundMusicSystem();    /* Restart the music */
  1150.     }
  1151. }
  1152.  
  1153. void ReadSystemJoystick(void)
  1154. {
  1155.     Word i;
  1156.     Word Index;
  1157.     
  1158.     MacKeys2Joy *MacPtr;
  1159.     Point MyPoint;
  1160.     union {
  1161.     unsigned char Keys[16];
  1162.     KeyMap Macy;
  1163.     } Keys;
  1164.  
  1165.     joystick1 = 0;            /* Assume that joystick not moved */
  1166.  
  1167.     i = GetAKey();                /* Allow menu events */
  1168.     if (i==0x1b) {            /* Pause key? */
  1169.         ShowMenuBar();
  1170.         InitCursor();
  1171.         PauseMenu = NewMenu(55,"\p<< Game is Paused! >>");
  1172.         InsertMenu(PauseMenu,0);
  1173.         DrawMenuBar();
  1174.         PauseSoundMusicSystem();    /* Pause the music */
  1175.         InPause = TRUE;                /* Hack to prevent the menu bar from disappearing */
  1176.         WaitTicksEvent(0);
  1177.         LastTicCount = ReadTick();    /* Reset the timer for the pause key */
  1178.         FixPauseMenu();                /* Exit pause */
  1179.         FixTheCursor();
  1180.     }
  1181.     
  1182.     /* Switch weapons like in DOOM! */
  1183.     
  1184.     if (i) {            /* Was a key hit? */
  1185.         i = toupper(i);    /* Force UPPER case */
  1186.         if (CheatIndex) {        /* Cheat in progress */
  1187.             if (CheatPtr[Cheat][CheatIndex]==i) {        /* Match the current string? */
  1188.                 ++CheatIndex;                /* Next char */
  1189.                 if (!CheatPtr[Cheat][CheatIndex]) {    /* End of the string? */
  1190.                     PlaySound(SND_BONUS);        /* I got a bonus! */
  1191.                     switch (Cheat) {        /* Execute the cheat */
  1192.                     case 1:
  1193.                         gamestate.godmode^=TRUE;            /* I am invincible! */
  1194.                         break;
  1195.                     case 5:
  1196.                         GiveKey(0);
  1197.                         GiveKey(1);        /* Award the keys */
  1198.                         break;
  1199.                     case 6:
  1200.                         playstate=EX_WARPED;        /* Force a jump to the next level */
  1201.                         nextmap = gamestate.mapon+1;    /* Next level */
  1202.                         if (MapListPtr->MaxMap<=nextmap) {    /* Too high? */
  1203.                             nextmap = 0;            /* Reset to zero */
  1204.                         }
  1205.                         break;
  1206.                     case 7:
  1207.                         ShowPush ^= TRUE;
  1208.                         break;
  1209.                     case 0:
  1210.                     case 4:
  1211.                         GiveKey(0);        /* Award the keys */
  1212.                         GiveKey(1);
  1213.                         gamestate.godmode = TRUE;            /* I am a god */
  1214.                     case 2:
  1215.                         gamestate.machinegun = TRUE;
  1216.                         gamestate.chaingun = TRUE;
  1217.                         gamestate.flamethrower = TRUE;
  1218.                         gamestate.missile = TRUE;
  1219.                         GiveAmmo(gamestate.maxammo);
  1220.                         GiveGas(99);
  1221.                         GiveMissile(99);
  1222.                         break;
  1223.                     case 3:
  1224.                         gamestate.maxammo = 999;
  1225.                         GiveAmmo(999);
  1226.                     }
  1227.                 }
  1228.             } else {
  1229.                 CheatIndex = 0;
  1230.                 goto TryFirst;
  1231.             }
  1232.         } else {
  1233. TryFirst:
  1234.             Index = 0;                /* Init the scan routine */
  1235.             do {
  1236.                 if (CheatPtr[Index][0] == i) {
  1237.                     Cheat = Index;        /* This is my current cheat I am scanning */
  1238.                     CheatIndex = 1;        /* Index to the second char */
  1239.                     break;                /* Exit */
  1240.                 }
  1241.             } while (++Index<8);        /* All words scanned? */
  1242.         }
  1243.         switch (ScanCode) {        /* Use the SCAN code to make sure I hit the right key! */
  1244.         case 0x12 :        /* 1 */
  1245.             gamestate.pendingweapon = WP_KNIFE;
  1246.             break;
  1247.         case 0x13 :     /* 2 */
  1248.             if (gamestate.ammo) {
  1249.                 gamestate.pendingweapon = WP_PISTOL;
  1250.             }
  1251.             break;
  1252.         case 0x14 :        /* 3 */
  1253.             if (gamestate.ammo && gamestate.machinegun) {
  1254.                 gamestate.pendingweapon = WP_MACHINEGUN;
  1255.             }
  1256.             break;
  1257.         case 0x15 :        /* 4 */
  1258.             if (gamestate.ammo && gamestate.chaingun) {
  1259.                 gamestate.pendingweapon = WP_CHAINGUN;
  1260.             }
  1261.             break;
  1262.         case 0x17 :        /* 5 */
  1263.             if (gamestate.gas && gamestate.flamethrower) {
  1264.                 gamestate.pendingweapon = WP_FLAMETHROWER;
  1265.             }
  1266.             break;    
  1267.         case 0x16 :        /* 6 */
  1268.             if (gamestate.missiles && gamestate.missile) {
  1269.                 gamestate.pendingweapon = WP_MISSILE;
  1270.             }
  1271.             break;
  1272.         case 0x41:        /* Keypad Period */
  1273.         case 0x2C:        /* Slash */
  1274.             joystick1 = JOYPAD_START; 
  1275.         }
  1276.     }
  1277.     
  1278.     GetKeys(Keys.Macy);        /* Get the keyboard from the mac */
  1279.     
  1280.     i = 0;                    /* Init the count */
  1281.     MacPtr = KeyMatrix;
  1282.     do {
  1283.         Index = MacPtr->Index;        /* Get the byte index */
  1284.         if (Keys.Keys[Index] & MacPtr->BitField) {
  1285.             joystick1 |= MacPtr->JoyValue;    /* Set the joystick value */
  1286.         }
  1287.         MacPtr++;                    /* Next index */
  1288.     } while (++i<33);                /* All done? */
  1289.     
  1290.     if (MouseEnabled) {                /* Mouse control turned on? */
  1291.         if (Button()) {                /* Get the mouse button */
  1292.             joystick1 |= JOYPAD_B;        /* Mouse button */
  1293.         }
  1294.         GetMouse(&MyPoint);            /* Get the mouse location */
  1295.         LocalToGlobal(&MyPoint);    /* Convert mouse to global coordinate system */
  1296.         if (joystick1&JOYPAD_TR) {    /* Strafing? */
  1297.             mousex += (MyPoint.h-MouseBaseX);    /* Move horizontally for strafe */
  1298.         } else {
  1299.             mouseturn += (MouseBaseX-MyPoint.h);    /* Turn left or right */
  1300.         }
  1301.         mousey += (MyPoint.v-MouseBaseY);        /* Forward motion */
  1302.         (*(unsigned short *) 0x082C) = MouseBaseY;    /* Set RawMouse */
  1303.         (*(unsigned short *) 0x082E) = MouseBaseX;
  1304.         (*(unsigned short *) 0x0828) = MouseBaseY;    /* MTemp */
  1305.         (*(unsigned short *) 0x082A) = MouseBaseX;    
  1306.         (*(Byte *) 0x08CE) = 255;                /* CrsrNew */
  1307.         (*(Byte *) 0x08CF) = 255;                /* CrsrCouple */
  1308.     }
  1309.     
  1310.     if (joystick1 & JOYPAD_TR) {        /* Handle the side scroll (Special case) */
  1311.         if (joystick1&JOYPAD_LFT) {
  1312.             joystick1 = (joystick1 & ~(JOYPAD_TR|JOYPAD_LFT)) | JOYPAD_TL;
  1313.         } else if (joystick1&JOYPAD_RGT) {
  1314.             joystick1 = joystick1 & ~JOYPAD_RGT;
  1315.         } else {
  1316.             joystick1 &= ~JOYPAD_TR;
  1317.         }
  1318.     }
  1319. }
  1320.  
  1321. /**********************************
  1322.  
  1323.     Handle GET PSYCHED!
  1324.     
  1325. **********************************/
  1326.  
  1327. static Rect PsychedRect;
  1328. static Word LeftMargin;
  1329. #define PSYCHEDWIDE 184
  1330. #define PSYCHEDHIGH 5
  1331. #define PSYCHEDX 20
  1332. #define PSYCHEDY 46
  1333. #define MAXINDEX (66+S_LASTONE)
  1334.         
  1335. /**********************************
  1336.  
  1337.     Draw the initial shape
  1338.         
  1339. **********************************/
  1340.  
  1341. void ShowGetPsyched(void)
  1342. {
  1343.     LongWord *PackPtr;
  1344.     Byte *ShapePtr;
  1345.     LongWord PackLength;
  1346.     Word X,Y;
  1347.     
  1348.     SetPort((WindowPtr)GameWindow);
  1349.     ClearTheScreen(BLACK);
  1350.     BlastScreen();
  1351.     PackPtr = LoadAResource(rGetPsychPic);
  1352.     PackLength = PackPtr[0];
  1353.     ShapePtr = AllocSomeMem(PackLength);
  1354.     DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
  1355.     X = (MacWidth-224)/2;    
  1356.     Y = (MacViewHeight-56)/2;
  1357.     DrawShape(X,Y,ShapePtr);
  1358.     FreeSomeMem(ShapePtr);
  1359.     ReleaseAResource(rGetPsychPic);
  1360.     BlastScreen();
  1361.     SetAPalette(rGamePal);
  1362.     SetPort((WindowPtr)GameWindow);
  1363.     ForeColor(redColor);
  1364.     PsychedRect.top = Y + PSYCHEDY + QDGameRect.top;
  1365.     PsychedRect.bottom = PsychedRect.top + PSYCHEDHIGH;
  1366.     PsychedRect.left = X + PSYCHEDX + QDGameRect.left;
  1367.     PsychedRect.right = PsychedRect.left;
  1368.     LeftMargin = PsychedRect.left;
  1369. }
  1370.  
  1371. /**********************************
  1372.  
  1373.     Update the thermomitor
  1374.     
  1375. **********************************/
  1376.  
  1377. void DrawPsyched(Word Index)
  1378. {
  1379.     Word Factor;
  1380.     
  1381.     Factor = Index * PSYCHEDWIDE;        /* Calc the relative X pixel factor */
  1382.     Factor = Factor / MAXINDEX;
  1383.     PsychedRect.left = PsychedRect.right;    /* Adjust the left pixel */
  1384.     PsychedRect.right = Factor+LeftMargin;
  1385.     PaintRect(&PsychedRect);        /* Draw the pixel in the bar */
  1386. }
  1387.  
  1388. /**********************************
  1389.  
  1390.     Erase the Get Psyched screen
  1391.     
  1392. **********************************/
  1393.  
  1394. void EndGetPsyched(void)
  1395. {
  1396.     ForeColor(blackColor);        /* Reset the color to black for high speed */
  1397.     SetAPalette(rBlackPal);        /* Zap the palette */
  1398. }
  1399.  
  1400. /**********************************
  1401.  
  1402.     Choose the game difficulty
  1403.     
  1404. **********************************/
  1405.  
  1406. static void DrawNewRect(DialogPtr theDialog,Word Item,Word Color)
  1407. {
  1408.     short iType;
  1409.     Handle iHndl;
  1410.     Rect iRect;
  1411.     
  1412.     ForeColor(Color);
  1413.     GetDialogItem(theDialog,Item, &iType, &iHndl, &iRect);
  1414.     InsetRect(&iRect,-4,-4);
  1415.     PenSize(3,3);        /* Nice thick line */
  1416.     FrameRect(&iRect);    
  1417.     PenNormal();
  1418. }
  1419.  
  1420. /**********************************
  1421.  
  1422.     Choose the game difficulty
  1423.     
  1424. **********************************/
  1425.  
  1426. static Word OldVal;            /* Make semi-global so the filter can use it as input */
  1427.  
  1428. Word ChooseGameDiff(void)
  1429. {
  1430.     ModalFilterUPP    theDialogFilter;
  1431.     DialogPtr MyDialog;
  1432.     short itemHit;
  1433.     Word donewithdialog;
  1434.     Word RetVal;
  1435.     Word OldTick;
  1436.     unsigned short DblClick;
  1437.     Byte OldPal[768];
  1438.         
  1439.     memcpy(OldPal,CurrentPal,768);
  1440.     SetPort((WindowPtr)GameWindow);
  1441.     FillRect(&BlackRect,&qd.black);
  1442.     SetAPalette(rGamePal);
  1443.     MyDialog = GetNewDialog(NewGameWin,0L,(WindowPtr)-1);        /* Open the dialog window */
  1444.     OldVal = difficulty+1;    /* Save the current difficulty */
  1445.     PlaySound(SND_MENU);
  1446.     CenterAWindow(MyDialog);
  1447.     ShowWindow(MyDialog);    /* Display with OK button framed */
  1448.     InitCursor();
  1449.     SetPort((WindowPtr) MyDialog);
  1450.     DrawNewRect(MyDialog,OldVal,blackColor);    
  1451.     DblClick = 0;
  1452.     donewithdialog = FALSE;
  1453.     RetVal = TRUE;            /* Assume ok */
  1454.  
  1455.     theDialogFilter = NewModalFilterProc(StandardModalFilterProc);
  1456.  
  1457.     do {
  1458.         ModalDialog(theDialogFilter, &itemHit);
  1459.         switch (itemHit) {
  1460.         case 1:
  1461.         case 2:
  1462.         case 3:
  1463.         case 4:                        /* The checkbox */
  1464.             if (OldVal!=itemHit) {
  1465.                 DrawNewRect(MyDialog,OldVal,whiteColor);        /* Erase the old rect */
  1466.                 DrawNewRect(MyDialog,itemHit,blackColor);
  1467.                 OldVal = itemHit;
  1468.             }
  1469.             PlaySound(SND_GUNSHT);            /* Gun shot */
  1470.             if (DblClick==itemHit) {        /* Hit the same item? */
  1471.                 if (((Word)ReadTick()-OldTick)<(Word)15) {    /* Double click time? */
  1472.                     donewithdialog = TRUE;
  1473.                     difficulty = OldVal-1;
  1474.                     break;        /* Ok! */
  1475.                 }
  1476.             }
  1477.             OldTick=ReadTick();        /* Save the tick mark */
  1478.             DblClick=itemHit;        /* Save the last item hit */
  1479.             break;
  1480.         case 5:
  1481.             RetVal = FALSE;
  1482.             donewithdialog = TRUE;
  1483.             PlaySound(SND_OK);
  1484.             break;
  1485.         case 6:                /* OK Button */
  1486.             donewithdialog = TRUE;
  1487.             difficulty = OldVal-1;
  1488.             PlaySound(SND_OK);
  1489.             break;
  1490.         }
  1491.     } while (!donewithdialog);
  1492.     DisposeRoutineDescriptor(theDialogFilter);
  1493.     DisposeDialog(MyDialog);
  1494.     SetAPalettePtr(OldPal);        /* Restore the palette */
  1495.     SetPort((WindowPtr) GameWindow);
  1496.     DrawWindow((WindowPtr)GameWindow);    /* Draw it NOW! */
  1497.     FixTheCursor();
  1498.     return RetVal;
  1499. }
  1500.  
  1501. static Byte BoxUp[] = {3,4,1,2};        /* Up/Down */
  1502. static Byte BoxLeft[] = {2,1,4,3};        /* Left/Right */
  1503. static Byte TabLeft[] = {2,3,4,1};        /* Tab */
  1504.  
  1505. pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  1506. {
  1507.     char    theChar;
  1508.     Handle    theHandle;
  1509.     short    theType;
  1510.     Rect    theRect;
  1511.  
  1512.     switch (theEvent->what) {
  1513.     case keyDown:
  1514.         theChar = toupper(theEvent->message & charCodeMask);
  1515.         switch (theChar) {
  1516.         
  1517.         case '8':        /* Up */
  1518.         case 0x1E:        /* Up */
  1519.         case '5':        /* Down */
  1520.         case '2':        /* Down */
  1521.         case 0x1F:        /* Down */
  1522.         case 'W':
  1523.         case 'S':
  1524.         case 'I':
  1525.         case 'K':
  1526.             *itemHit = BoxUp[OldVal-1];
  1527.             return TRUE;
  1528.             
  1529.         case '4':        /* Left */
  1530.         case '6':        /* Right */
  1531.         case 0x1C:        /* Left */
  1532.         case 0x1D:        /* Right */
  1533.         case 'A':
  1534.         case 'D':
  1535.         case 'J':
  1536.         case 'L':
  1537.             *itemHit = BoxLeft[OldVal-1];
  1538.             return TRUE;
  1539.         
  1540.         case 9:
  1541.             *itemHit = TabLeft[OldVal-1];
  1542.             return TRUE;
  1543.             
  1544.         case 0x0D:        /*    Return */
  1545.         case 0x03:        /*    Enter */
  1546.             *itemHit = 6;
  1547.             return (TRUE);
  1548.  
  1549.         case 'Q':        /* Cmd-Q */
  1550.         case '.':        /* Cmd-Period */
  1551.             if (theEvent->modifiers & cmdKey) {
  1552.         case 0x1b:        /* Esc */
  1553.                 *itemHit = 5;
  1554.                 return (TRUE);
  1555.             }
  1556.             break;
  1557.         }
  1558.         break;
  1559.     case updateEvt:
  1560.         GetDialogItem(theDialog, 6, &theType, &theHandle, &theRect);
  1561.         InsetRect(&theRect, -4, -4);
  1562.         PenSize(3, 3);
  1563.         FrameRoundRect(&theRect, 16, 16);
  1564.     }
  1565.     return (FALSE);        //¥    Tells dialog manager to handle the event
  1566. }
  1567.  
  1568.  
  1569. /**********************************
  1570.  
  1571.     Load the prefs file into memory and use defaults 
  1572.     for ANY errors that could occur
  1573.     
  1574. **********************************/
  1575.  
  1576. typedef struct {        /* Save game data field */
  1577.     unsigned short State;        /* Game state flags */
  1578.     unsigned short Mouse;        /* Mouse control */
  1579.     unsigned short QuickDraw;    /* Quickdraw for updates */
  1580.     unsigned short Goveror;        /* Speed governor */
  1581.     unsigned short ViewSize;    /* Game screen size */
  1582.     unsigned short Difficulty;    /* Game difficulty */
  1583.     unsigned short Ignore;        /* Ignore message flag */
  1584. } Prefs_t;
  1585.  
  1586. void LoadPrefs(void)
  1587. {
  1588.     Prefs_t Prefs;
  1589.     
  1590.     Prefs.State = 3;            /* Assume sound & music enabled */
  1591.     Prefs.Mouse = FALSE;        /* Mouse control shut off */
  1592.     Prefs.QuickDraw = TRUE;        /* Use quickdraw for screen updates */
  1593.     Prefs.Goveror = TRUE;        /* Enable speed governor */
  1594.     Prefs.ViewSize = 0;            /* 320 mode screen */
  1595.     Prefs.Difficulty = 2;        /* Medium difficulty */
  1596.     Prefs.Ignore = FALSE;        /* Enable message */
  1597.     
  1598.     InitPrefsFile('WOLF',(Byte *)"Wolfenstein 3D Prefs");        /* Create the prefs file (If it doesn't exist) */
  1599.     LoadPrefsFile((Byte *)&Prefs,sizeof(Prefs));        /* Load in the prefs (Assume it may NOT!) */
  1600.     SystemState = Prefs.State;    /* Store the defaults from either the presets or the file */
  1601.     MouseEnabled = Prefs.Mouse;
  1602.     DoQuickDraw = Prefs.QuickDraw;
  1603.     SlowDown = Prefs.Goveror;
  1604.     GameViewSize = Prefs.ViewSize;
  1605.     difficulty = Prefs.Difficulty;
  1606.     IgnoreMessage = Prefs.Ignore;
  1607. }
  1608.  
  1609. /**********************************
  1610.  
  1611.     Save the prefs file to disk but ignore any errors
  1612.     
  1613. **********************************/
  1614.  
  1615. void SavePrefs(void)
  1616. {
  1617.     Prefs_t Prefs;            /* Structure to save to disk */
  1618.     Prefs.State = SystemState;    /* Init the prefs structure */
  1619.     Prefs.Mouse = MouseEnabled;
  1620.     Prefs.QuickDraw = DoQuickDraw;
  1621.     Prefs.Goveror = SlowDown;
  1622.     Prefs.ViewSize = GameViewSize;
  1623.     Prefs.Difficulty =    difficulty;
  1624.     Prefs.Ignore = IgnoreMessage;
  1625.     SavePrefsFile((Byte *)&Prefs,sizeof(Prefs));    /* Save the prefs file */
  1626. }
  1627.  
  1628. /**********************************
  1629.  
  1630.     Save the game
  1631.     
  1632. **********************************/
  1633.  
  1634. #ifdef __powerc
  1635. Byte MachType[4] = "PPC3";
  1636. #else
  1637. Byte MachType[4] = "68K3";
  1638. #endif
  1639.  
  1640. void SaveGame(void)
  1641. {
  1642.     short FileRef;
  1643.     long Count;
  1644.     Word PWallWord;
  1645.     
  1646.     HCreate(SaveFileVol,SaveFileParID,SaveFileName,'WOLF','SAVE');        /* Create the save game file */
  1647.     if (HOpen(SaveFileVol,SaveFileParID,SaveFileName,fsWrPerm,&FileRef)) {    /* Can I open it? */
  1648.         return;                /* Abort! */
  1649.     }
  1650.  
  1651.     Count = 4;                            /* Default length */
  1652.     FSWrite(FileRef,&Count,&MachType);    /* Save a machine type ID */
  1653.     Count = sizeof(unsigned short);
  1654.     FSWrite(FileRef,&Count,&MapListPtr->MaxMap);     /* Number of maps (ID) */            
  1655.     Count = sizeof(gamestate);            
  1656.     FSWrite(FileRef,&Count,&gamestate);        /* Save the game stats */
  1657.     Count = sizeof(PushWallRec);
  1658.     FSWrite(FileRef,&Count,&PushWallRec);    /* Save the pushwall stats */
  1659.     
  1660.     Count = sizeof(nummissiles);
  1661.     FSWrite(FileRef,&Count,&nummissiles);    /* Save missiles in motion */
  1662.     if (nummissiles) {
  1663.         Count = nummissiles*sizeof(missile_t);
  1664.         FSWrite(FileRef,&Count,&missiles[0]);
  1665.     }
  1666.     Count = sizeof(numactors);
  1667.     FSWrite(FileRef,&Count,&numactors);        /* Save actors */
  1668.     if (numactors) {
  1669.         Count = numactors*sizeof(actor_t);
  1670.         FSWrite(FileRef,&Count,&actors[0]);
  1671.     }
  1672.     Count = sizeof(numdoors);
  1673.     FSWrite(FileRef,&Count,&numdoors);        /* Save doors */
  1674.     if (numdoors) {
  1675.         Count = numdoors*sizeof(door_t);
  1676.         FSWrite(FileRef,&Count,&doors[0]);
  1677.     }
  1678.     Count = sizeof(numstatics);
  1679.     FSWrite(FileRef,&Count,&numstatics);
  1680.     if (numstatics) {
  1681.         Count = numstatics*sizeof(static_t);
  1682.         FSWrite(FileRef,&Count,&statics[0]);
  1683.     }
  1684.     Count = 64*64;
  1685.     FSWrite(FileRef,&Count,MapPtr);
  1686.     Count = sizeof(tilemap);                /* Tile map */
  1687.     FSWrite(FileRef,&Count,&tilemap);
  1688.  
  1689.     Count = sizeof(ConnectCount);
  1690.     FSWrite(FileRef,&Count,&ConnectCount);
  1691.     if (ConnectCount) {
  1692.         Count = ConnectCount * sizeof(connect_t);
  1693.         FSWrite(FileRef,&Count,&areaconnect[0]);
  1694.     }
  1695.     Count = sizeof(areabyplayer);
  1696.     FSWrite(FileRef,&Count,&areabyplayer[0]);
  1697.     Count = (128+5)*64;
  1698.     FSWrite(FileRef,&Count,&textures[0]);
  1699.     Count = sizeof(Word);
  1700.     PWallWord = 0;        /* Assume no pushwall pointer in progress */
  1701.     if (pwallseg) {
  1702.         PWallWord = (pwallseg-(saveseg_t*)nodes)+1;        /* Convert to number offset */
  1703.     } 
  1704.     FSWrite(FileRef,&Count,&PWallWord);
  1705.     Count = MapPtr->numnodes*sizeof(savenode_t);    /* How large is the BSP tree? */
  1706.     FSWrite(FileRef,&Count,nodes);            /* Save it to disk */
  1707.     FSClose(FileRef);                        /* Close the file */
  1708.     PlaySound(SND_BONUS);
  1709. }
  1710.  
  1711. /**********************************
  1712.  
  1713.     Load the game    
  1714.     
  1715. **********************************/
  1716.  
  1717. void *SaveRecord;
  1718. void *SaveRecordMem;
  1719.  
  1720. Boolean LoadGame(void)
  1721. {
  1722.     LongWord FileSize;
  1723.     union {
  1724.         Byte *B;
  1725.         unsigned short *S;
  1726.         Word *W;
  1727.         LongWord *L;
  1728.     } FilePtr;
  1729.     void *TheMem;
  1730.     short FileRef;
  1731.  
  1732.     if (HOpen(SaveFileVol, SaveFileParID, SaveFileName, fsRdPerm, &FileRef)) {
  1733.         return FALSE;
  1734.     }
  1735.     GetEOF(FileRef,(long*)&FileSize);        /* Get the size of the file */
  1736.     FilePtr.B = TheMem = AllocSomeMem(FileSize);    /* Get memory for the file */
  1737.     if (!FilePtr.B) {                        /* No memory! */
  1738.         return FALSE;
  1739.     }
  1740.     FSRead(FileRef,(long*)&FileSize,(Ptr)FilePtr.B);    /* Open the file */
  1741.     FSClose(FileRef);                        /* Close the file */
  1742.     if (memcmp(MachType,FilePtr.B,4)) {        /* Is this the proper machine type? */
  1743.         goto Bogus;                            
  1744.     }
  1745.     FilePtr.B+=4;                            /* Index past signature */    
  1746.     if (MapListPtr->MaxMap!=*FilePtr.S) {    /* Map count the same? */
  1747.         goto Bogus;                            /* Must be differant game */
  1748.     }
  1749.     ++FilePtr.S;                            /* Index past count */
  1750.     memcpy(&gamestate,FilePtr.B,sizeof(gamestate));    /* Reset the game state */
  1751.     SaveRecord = FilePtr.B;
  1752.     SaveRecordMem = TheMem;
  1753.     return TRUE;
  1754.     
  1755. Bogus:
  1756.     FreeSomeMem(TheMem);
  1757.     return FALSE;
  1758. }
  1759.  
  1760. void FinishLoadGame(void) 
  1761. {    
  1762.     union {
  1763.         Byte *B;
  1764.         unsigned short *S;
  1765.         Word *W;
  1766.         LongWord *L;
  1767.     } FilePtr;
  1768.     
  1769.     FilePtr.B = SaveRecord;
  1770.     
  1771.     memcpy(&gamestate,FilePtr.B,sizeof(gamestate));    /* Reset the game state */
  1772.     FilePtr.B+=sizeof(gamestate);
  1773.     
  1774.     memcpy(&PushWallRec,FilePtr.B,sizeof(PushWallRec));                /* Record for the single pushwall in progress */
  1775.     FilePtr.B+=sizeof(PushWallRec);
  1776.     
  1777.     nummissiles = *FilePtr.W;
  1778.     ++FilePtr.W;
  1779.     if (nummissiles) {
  1780.         memcpy(&missiles[0],FilePtr.B,sizeof(missile_t)*nummissiles);
  1781.         FilePtr.B += sizeof(missile_t)*nummissiles;
  1782.     }
  1783.  
  1784.     numactors = *FilePtr.W;
  1785.     ++FilePtr.W;
  1786.     if (numactors) {
  1787.         memcpy(&actors[0],FilePtr.B,sizeof(actor_t)*numactors);
  1788.         FilePtr.B += sizeof(actor_t)*numactors;
  1789.     }
  1790.     
  1791.     numdoors = *FilePtr.W;
  1792.     ++FilePtr.W;
  1793.     if (numdoors) {
  1794.         memcpy(&doors[0],FilePtr.B,sizeof(door_t)*numdoors);
  1795.         FilePtr.B += sizeof(door_t)*numdoors;
  1796.     }
  1797.  
  1798.     numstatics = *FilePtr.W;
  1799.     ++FilePtr.W;
  1800.     if (numstatics) {
  1801.         memcpy(&statics[0],FilePtr.B,sizeof(static_t)*numstatics);
  1802.         FilePtr.B += sizeof(static_t)*numstatics;
  1803.     }
  1804.     memcpy(MapPtr,FilePtr.B,64*64);
  1805.     FilePtr.B += 64*64;
  1806.     memcpy(&tilemap,FilePtr.B,sizeof(tilemap));                        /* Tile map */
  1807.     FilePtr.B += sizeof(tilemap);        /* Index past data */
  1808.     
  1809.     ConnectCount = *FilePtr.W;        /* Number of valid interconnects */
  1810.     FilePtr.W++;                
  1811.     if (ConnectCount) {
  1812.         memcpy(areaconnect,FilePtr.B,sizeof(connect_t)*ConnectCount);    /* Is this area mated with another? */
  1813.         FilePtr.B+= sizeof(connect_t)*ConnectCount;
  1814.     }    
  1815.     memcpy(areabyplayer,FilePtr.B,sizeof(areabyplayer));
  1816.     FilePtr.B+=sizeof(areabyplayer);    /* Which areas can I see into? */
  1817.     
  1818.     memcpy(&textures[0],FilePtr.B,(128+5)*64);
  1819.     FilePtr.B+=((128+5)*64);                /* Texture array for pushwalls */
  1820.     
  1821.     pwallseg = 0;            /* Assume bogus */
  1822.     if (*FilePtr.W) {
  1823.         pwallseg = (saveseg_t *)nodes;
  1824.         pwallseg = &pwallseg[*FilePtr.W-1];
  1825.     }
  1826.     ++FilePtr.W;
  1827.     memcpy(nodes,FilePtr.B,MapPtr->numnodes*sizeof(savenode_t)); 
  1828. /*    FilePtr.B+=(MapPtr->numnodes*sizeof(savenode_t));    /* Next entry */
  1829.     
  1830.     FreeSomeMem(SaveRecordMem);
  1831. }
  1832.  
  1833. /**********************************
  1834.  
  1835.     Process an alert and center it on my game monitor
  1836.     Note : I am cheating like a son of a bitch by modifing the
  1837.     resources directly!
  1838.     
  1839. **********************************/
  1840.  
  1841. static Word DoMyAlert(Word AlertNum)
  1842. {
  1843.     Word Val;
  1844.     Rect **AlertRect;        /* Handle to the alert rect */
  1845.     Rect MyRect;
  1846.     
  1847.     InitCursor();            /* Fix the cursor */
  1848.     AlertRect = (Rect **)GetResource('ALRT',AlertNum);        /* Load in the template */
  1849.     MyRect = **AlertRect;        /* Copy the rect */
  1850.     MyRect.right -= MyRect.left;    /* Get the width */
  1851.     MyRect.bottom -= MyRect.top;    /* Get the height */
  1852.     CenterSFWindow((Point *)&MyRect,MyRect.right,MyRect.bottom);    /* Center the window */
  1853.     MyRect.right += MyRect.left;    /* Fix the rect */
  1854.     MyRect.bottom += MyRect.top;
  1855.     **AlertRect = MyRect;
  1856.     ChangedResource((Handle)AlertRect);
  1857.     Val = Alert(AlertNum,nil);
  1858.     if (!InPause) {        /* If paused then don't fix the cursor */
  1859.         FixTheCursor();
  1860.     }
  1861.     return Val;
  1862. }
  1863.  
  1864. /**********************************
  1865.  
  1866.     Beg for $$$ at the end of the shareware version
  1867.     
  1868. **********************************/
  1869.  
  1870. void ShareWareEnd(void)
  1871. {
  1872.     SetAPalette(rGamePal);
  1873.     DoMyAlert(EndGameWin);
  1874.     SetAPalette(rBlackPal);
  1875. }
  1876.  
  1877. /**********************************
  1878.  
  1879.     Show the standard file dialog 
  1880.     for opening a new game
  1881.         
  1882. **********************************/
  1883.  
  1884. SFTypeList MyList = {'SAVE'};
  1885. SFReply Reply;
  1886.  
  1887. static void CenterSFWindow(Point *MyPoint,Word Width,Word Height)
  1888. {
  1889.     GDHandle MainDevice;
  1890.     Rect TheRect;
  1891.     Word H,W;            /* Device width of main device */
  1892.     
  1893.     if (gMainGDH) {        /* Has the video device been selected? */
  1894.         MyPoint->v = ((MonitorHeight-Height)/3)+BlackRect2.top;    /* Center the window then */
  1895.         MyPoint->h = ((MonitorWidth-Width)/2)+BlackRect2.left;
  1896.         return;
  1897.     }
  1898.     MainDevice = GetMainDevice();        /* Get the default device */
  1899.     TheRect = (**MainDevice).gdRect;    /* Get the rect of the device */
  1900.     H = TheRect.bottom - TheRect.top;    /* Get the size of the video screen */
  1901.     W = TheRect.right - TheRect.left;
  1902.     MyPoint->v = ((H-Height)/3)+TheRect.top;    /* Center the window */
  1903.     MyPoint->h = ((W-Width)/2)+TheRect.left;    
  1904. }
  1905.  
  1906. static void CenterAWindow(WindowPtr MyWindow)
  1907. {
  1908.     Rect MyRect;
  1909.     Point MyPoint;
  1910.     
  1911.     MyRect = ((WindowPeek)MyWindow)->port.portRect;
  1912.     CenterSFWindow(&MyPoint,MyRect.right-MyRect.left,MyRect.bottom-MyRect.top);
  1913.     MoveWindow(MyWindow,MyPoint.h,MyPoint.v,FALSE);
  1914. }
  1915.  
  1916.  
  1917. Boolean ChooseLoadGame(void)
  1918. {
  1919.     long ProcID;
  1920.     Point MyPoint;
  1921.     
  1922.     InitCursor();
  1923.     CenterSFWindow(&MyPoint,348,136);
  1924.     SFGetFile(MyPoint,0,0,1,MyList,0,&Reply);
  1925.     FixTheCursor();
  1926.     if (!Reply.good) {        /* Pressed cancel? */
  1927.         return FALSE;
  1928.     }
  1929.     SaveFileName = (Byte *)&Reply.fName;
  1930.     SaveFileVol = Reply.vRefNum;
  1931.     GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
  1932.     return TRUE;
  1933. }
  1934.  
  1935. /**********************************
  1936.  
  1937.     Show the standard file dialog 
  1938.     for saving a new game
  1939.         
  1940. **********************************/
  1941.  
  1942. Boolean ChooseSaveGame(void)
  1943. {
  1944.     Byte *SaveTemp;
  1945.     Point MyPoint;
  1946.     long ProcID;
  1947.     
  1948.     InitCursor();
  1949.     SaveTemp = SaveFileName;
  1950.     if (!SaveTemp) {
  1951.         SaveTemp = "\pUntitled";
  1952.     }
  1953.     CenterSFWindow(&MyPoint,304,104);
  1954.     SFPutFile(MyPoint,"\pSave your game as:",SaveTemp,0,&Reply);
  1955.     FixTheCursor();
  1956.     if (!Reply.good) {
  1957.         return FALSE;
  1958.     }
  1959.     SaveFileName = (Byte *)&Reply.fName;
  1960.     SaveFileVol = Reply.vRefNum;
  1961.     GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
  1962.     return TRUE;
  1963. }
  1964.  
  1965. /**********************************
  1966.  
  1967.     Process Apple Events
  1968.     
  1969. **********************************/
  1970. #if 1
  1971. struct AEinstalls {
  1972.     AEEventClass theClass;
  1973.     AEEventID theEvent;
  1974.     void *Code;
  1975.     AEEventHandlerUPP theProc;
  1976. };
  1977. typedef struct AEinstalls AEinstalls;
  1978.  
  1979.  
  1980. static OSErr GotRequiredParams(AppleEvent *theAppleEvent)
  1981. {
  1982.     DescType returnedType;
  1983.     Size actualSize;
  1984.     OSErr theErr;
  1985.     
  1986.     theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
  1987.                             typeWildCard, &returnedType, nil, 0, &actualSize);
  1988.     if (theErr == errAEDescNotFound)
  1989.         return noErr;
  1990.     if (!theErr)
  1991.         return errAEParamMissed;
  1992.     return theErr;
  1993. }
  1994.  
  1995. /* This is the standard Open Application event.  */
  1996. static pascal OSErr AEOpenHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refIn)
  1997. {
  1998.     OSErr theErr;
  1999.     
  2000.     // This event occurs when the application is opened.  In most cases
  2001.     // nothing needs to be done, but we must make sure that we received
  2002.     // no parameters, since none are supposed to be received.
  2003.     
  2004.     theErr = GotRequiredParams(theAppleEvent);
  2005.     if (theErr)
  2006.         return theErr;
  2007.         
  2008.     // do whatever is needed (e.g., open new untitled document)
  2009.     
  2010.     return noErr;
  2011. }
  2012.  
  2013. /* Open Doc, opens our documents.  Remember, this can happen at application start AND */
  2014. /* anytime else.  If your app is up and running and the user goes to the desktop, hilites one */
  2015. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  2016. /* handler will get called. Which means you don't do any initialization of globals here, or */
  2017. /* anything else except open then doc.  */
  2018. /* SO-- Do NOT assume that you are at app start time in this */
  2019. /* routine, or bad things will surely happen to you. */
  2020.  
  2021. static pascal OSErr AEOpenDocHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
  2022. {
  2023.     AEDescList docList;
  2024.     OSErr theErr;
  2025.     long index, itemsInList;
  2026.     Size actualSize;
  2027.     AEKeyword keywd;
  2028.     DescType returnedType;
  2029.     FSSpec theFSS;
  2030.     
  2031.     // In response to this event, we must open all documents specified in
  2032.     // the Apple Event.
  2033.  
  2034.     AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
  2035.     
  2036.     // check for missing required parameters
  2037.     theErr = GotRequiredParams(theAppleEvent);
  2038.     if (theErr != noErr)
  2039.         return AEDisposeDesc(&docList);
  2040.     
  2041.     // count the number of descriptor records in the list
  2042.     theErr = AECountItems(&docList, &itemsInList);
  2043.     
  2044.     // get each descriptor record from the list, coerce the returned
  2045.     // data to an FSSpec record, and open the associated file
  2046.     index = 1;
  2047.     if (index <= itemsInList) {
  2048.         AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
  2049.                         (Ptr)&theFSS, sizeof(theFSS), &actualSize);
  2050.         // open FSSpec
  2051.         OpenPending = TRUE;
  2052.         SaveFileVol = theFSS.vRefNum;
  2053.         SaveFileParID = theFSS.parID;
  2054.         SaveFileName = (Byte *)&Reply.fName;
  2055.         memcpy(&Reply.fName,&theFSS.name,*theFSS.name+1);
  2056.     }
  2057.     
  2058.     AEDisposeDesc(&docList);
  2059.     
  2060.     return noErr;
  2061. }
  2062.  
  2063.  
  2064. static pascal OSErr AEPrintHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
  2065. {
  2066.     AEDescList docList;
  2067.     OSErr theErr;
  2068.     long index, itemsInList;
  2069.     Size actualSize;
  2070.     AEKeyword keywd;
  2071.     DescType returnedType;
  2072.     FSSpec theFSS;
  2073.     
  2074.     // In response to this event, we must print all documents specified in
  2075.     // the Apple Event.
  2076.  
  2077.     theErr = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
  2078.     
  2079.     // check for missing required parameters
  2080.     theErr = GotRequiredParams(theAppleEvent);
  2081.     if (theErr != noErr)
  2082.         return AEDisposeDesc(&docList);
  2083.     
  2084.     // count the number of descriptor records in the list
  2085.     theErr = AECountItems(&docList, &itemsInList);
  2086.     
  2087.     // get each descriptor record from the list, coerce the returned
  2088.     // data to an FSSpec record, and open the associated file
  2089.     for (index = 1; index <= itemsInList; index++)
  2090.     {
  2091.         theErr = AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
  2092.                         (Ptr)&theFSS, sizeof(theFSS), &actualSize);
  2093.         // print FSSpec <no printing in this application>
  2094.     }
  2095.     
  2096.     AEDisposeDesc(&docList);
  2097.     
  2098.     return noErr;
  2099. }
  2100.  
  2101. /* Standard Quit event handler, to handle a Quit event from the Finder, for example.
  2102.     Note that we may not exit from the AppleEvent handler!  We have to set a flag,
  2103.     and exit from within the normal application code.  */
  2104.  
  2105. static pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  2106. {
  2107.     QuitFlag = 1;        /* I quit! */
  2108.     return noErr;
  2109. }
  2110.  
  2111. /* InitAEStuff installs my appleevent handlers */
  2112. void InitAEStuff(void);
  2113.  
  2114. static AEinstalls HandlersToInstall[] =  {
  2115.     {kCoreEventClass, kAEOpenApplication,AEOpenHandler,0},  
  2116.     {kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler,0},  
  2117.     {kCoreEventClass, kAEQuitApplication, AEQuitHandler,0},  
  2118.     {kCoreEventClass, kAEPrintDocuments, AEPrintHandler,0}
  2119. };
  2120.  
  2121. void InitAEStuff(void)
  2122. {
  2123.  
  2124.     Word i;
  2125.     
  2126.     /* Check this machine for AppleEvents.  If they are not here (ie not 7.0)
  2127.     *   then we return. */
  2128.     
  2129.     #ifndef __powerc
  2130.        long aLong;
  2131.     short Code,Count;
  2132.     short Index;
  2133.     AppFile Stuff;
  2134.     
  2135.     /* This is for the WONDERFUL system 6.0.7 filenames */
  2136.     /* Only execute on 680x0 macs */
  2137.     
  2138.     CountAppFiles(&Code,&Count);
  2139.     for (Index=1;Index<=Count;++Count) {
  2140.         GetAppFiles(Index,&Stuff);
  2141.         if (Index==1) {
  2142.             OpenPending = TRUE;
  2143.             SaveFileVol = Stuff.vRefNum;
  2144.             SaveFileName = (Byte *)&Reply.fName;
  2145.             memcpy(&Reply.fName,&Stuff.fName,*Stuff.fName+1);
  2146.             GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&aLong);
  2147.         }
  2148.         ClrAppFiles(Index);
  2149.     }
  2150.     if (Gestalt(gestaltAppleEventsAttr, &aLong)) {    /* Are Apple events present? */
  2151.         return;                    
  2152.     }
  2153.     if (!(aLong & (1<<gestaltAppleEventsPresent))) {
  2154.         return;
  2155.     }
  2156.     #endif
  2157.     
  2158.     /* The following series of calls installs all our AppleEvent Handlers.
  2159.     *   These handlers are added to the application event handler list that 
  2160.     *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
  2161.     *   and we call AEProcessEvent, the AppleEvent manager will check our
  2162.     *   list of handlers and dispatch to it if there is one.
  2163.     */
  2164.     i = 0;
  2165.     do {
  2166.         HandlersToInstall[i].theProc = NewAEEventHandlerProc(HandlersToInstall[i].Code);
  2167.         AEInstallEventHandler(HandlersToInstall[i].theClass, HandlersToInstall[i].theEvent,
  2168.                                             HandlersToInstall[i].theProc,0,FALSE);
  2169.     } while (++i<4); 
  2170. }
  2171. #endif
  2172.  
  2173. /**********************************
  2174.  
  2175.     Make the cursor disappear if needed
  2176.     
  2177. **********************************/
  2178.  
  2179. static void FixTheCursor(void)
  2180. {
  2181.     InitCursor();
  2182.     if (MouseEnabled && !InPause) {
  2183.         HideCursor();
  2184.     }
  2185. }
  2186.  
  2187. /**********************************
  2188.  
  2189.     Show a watch cursor
  2190.     
  2191. **********************************/
  2192.  
  2193. static void WaitCursor(void)
  2194. {
  2195.     SetCursor(*WatchHandle);
  2196. }
  2197.